package com.apes.fico.finance.service;

import com.apes.fico.finance.model.costcollect.OperatingCosts;
import com.apes.fico.finance.model.costcollect.OperatingCostsItem;
import com.apes.fico.finance.model.costcollect.ProportionServeType;
import com.apes.fico.finance.model.costcollect.TypeCost;
import com.apes.fico.finance.model.newcost.NewOperatingCosts;
import com.apes.fico.finance.model.newcost.NewOperatingCostsItem;
import com.apes.fico.finance.respository.*;
import com.apes.framework.api.DomainService;
import com.apes.framework.plugin.esb.api.SimpleRequest;
import com.apes.framework.util.Arith;
import com.apes.framework.util.DateUtil;
import com.apes.framework.util.MapUtil;
import com.apes.scm.masterdata.enumeration.repository.EnumerationRepository;
import com.apes.scm.masterdata.frame.model.Dept;
import com.apes.scm.masterdata.frame.repository.DeptRepository;
import com.apes.scm.masterdata.party.model.PartyRole;
import com.apes.scm.masterdata.party.repository.PartyRoleRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author: cyy
 * @create: 2022-12-13 14:22
 */
@Service("operatingCostsService")
public class OperatingCostsService extends DomainService {
    @Autowired
    private OperatingCostsRepository operatingCostsRepository;
    @Autowired
    private ProportionServeTypeRepository proportionServeTypeRepository;
    @Autowired
    private GLVoucherRepository glVoucherRepository;
    @Autowired
    private DeptRepository deptRepository;
    @Autowired
    private EnumerationRepository enumerationRepository;
    @Autowired
    private TypeCostRepository typeCostRepository;
    @Autowired
    private PartyRoleRepository partyRoleRepository;
    @Autowired
    private NewOperatingCostsRepository newOperatingCostsRepository;

    //保存后生成运营成本表,注意区分计提与实际
    public void costAccumulation(SimpleRequest request){
        Map map = request.getMap();
        Double amt = Double.parseDouble(map.get("amt").toString());
        String state = map.get("state").toString();
        Date yearMonth = DateUtil.parse(map.get("yearMonth").toString());
        String months = DateUtil.format(yearMonth, "MM");
        String years = DateUtil.format(yearMonth, "YYYY");
        Dept dept = deptRepository.findOne(map.get("dept").toString());
        TypeCost typeCost = typeCostRepository.findOne(map.get("typeCost").toString());
        PartyRole company = partyRoleRepository.findOne(map.get("company").toString());

        PartyRole declareCompany = null;
        //通过年月部门和成本类别找到唯一
        OperatingCosts operatingCosts = operatingCostsRepository.findOldOperatingCosts(months,years,dept.getId(),typeCost.getId(),company.getId()).stream().findFirst().orElse(null);
        if(operatingCosts == null){
            OperatingCosts newOperatingCosts = new OperatingCosts();
            newOperatingCosts.setDeptCompany(company);
            newOperatingCosts.setDept(dept);
            newOperatingCosts.setProofDigest(dept.getName() + years + "-" + months + typeCost.getName());
            //设置申报公司
            if (!ObjectUtils.isEmpty(map.get("declareCompany"))){
                declareCompany = MapUtil.getO(map.get("declareCompany"),PartyRole.class);
                newOperatingCosts.setCompany(declareCompany);
            }
            newOperatingCosts.setYearMonth(yearMonth);
            newOperatingCosts.setCostType(enumerationRepository.findOne(map.get("costType").toString()));
            newOperatingCosts.setTypeCost(typeCost);
            if("provision".equals(state)){
                newOperatingCosts.setAccrualDate(new Date());
                newOperatingCosts.setAccrualAmt(amt);
            } else if("actually".equals(state)){
                newOperatingCosts.setRealDate(new Date());
                newOperatingCosts.setRealAmt(amt);
            } else if("bluntProvision".equals(state)){
                newOperatingCosts.setBluntProvisionDate(new Date());
                newOperatingCosts.setBluntProvisionAmt(amt);
            } else if("bluntActually".equals(state)){
                newOperatingCosts.setBluntActuallyDate(new Date());
                newOperatingCosts.setBluntActuallyAmt(amt);
            }
            newOperatingCosts.setOperatingCostsItemSet(share(new HashSet(),newOperatingCosts,state,amt));
            operatingCostsRepository.saveAndFlush(newOperatingCosts);
        }else {
            if("provision".equals(state)){
                operatingCosts.setAccrualDate(new Date());
                operatingCosts.setAccrualAmt(operatingCosts.getAccrualAmt() + amt);
            } else if("actually".equals(state)){
                operatingCosts.setRealDate(new Date());
                operatingCosts.setRealAmt(operatingCosts.getRealAmt() + amt);
//                List<GLVoucher> glVouchers = glVoucherRepository.findAllByBusinessId(operatingCosts.getId());
//                glVouchers.stream().forEach(glVoucher -> this.invoke("finance.GLVoucher.reversal", MapUtil.mapped(glVoucher)));
            } else if("bluntProvision".equals(state)){
                operatingCosts.setBluntProvisionDate(new Date());
                operatingCosts.setBluntProvisionAmt(operatingCosts.getBluntProvisionAmt() + amt);
            } else if("bluntActually".equals(state)){
                operatingCosts.setBluntActuallyDate(new Date());
                operatingCosts.setBluntActuallyAmt(operatingCosts.getBluntActuallyAmt() + amt);
            }
            operatingCosts.setOperatingCostsItemSet(share(operatingCosts.getOperatingCostsItemSet(),operatingCosts,state,amt));
            operatingCostsRepository.saveAndFlush(operatingCosts);
        }

        //生成经营成本明细
        saveNewOperatingCots(map,typeCost,company,dept);
    }

    //分摊明细
    public Set<OperatingCostsItem> share(Set<OperatingCostsItem> operatingCostsItemSet,OperatingCosts operatingCosts,String state,Double amt){
        //获取比例
        Date yearMonth = operatingCosts.getYearMonth();
        String months = DateUtil.format(yearMonth, "MM");
        String years = DateUtil.format(yearMonth, "YYYY");
        List<ProportionServeType> proportionServeTypeList = proportionServeTypeRepository.findByYearMonthAndDept(months,years,operatingCosts.getDept().getId());
        if(operatingCostsItemSet.size() == 0){
            proportionServeTypeList.forEach(proportionServeType -> {
                OperatingCostsItem operatingCostsItem = new OperatingCostsItem();
                operatingCostsItem.setCostType(operatingCosts.getCostType());
                operatingCostsItem.setServeType(proportionServeType.getServeType());
                operatingCostsItem.setTypeCost(operatingCosts.getTypeCost());
                //注意区分计提与实际
                if("provision".equals(state)){
                    operatingCostsItem.setAccrualDate(new Date());
                    operatingCostsItem.setAccrualAmt( Arith.round(operatingCosts.getAccrualAmt() * proportionServeType.getProportion(),2));
                    operatingCosts.setAccrualState("done");
                } else if("actually".equals(state)){
                    operatingCostsItem.setRealDate(new Date());
                    operatingCostsItem.setRealAmt( Arith.round(operatingCosts.getRealAmt() * proportionServeType.getProportion(),2));
                    operatingCosts.setRealState("done");
                } else if("bluntProvision".equals(state)){
                    operatingCostsItem.setBluntProvisionDate(new Date());
                    operatingCostsItem.setBluntProvisionAmt(Arith.round(operatingCosts.getBluntProvisionAmt() * proportionServeType.getProportion(),2));
                    operatingCosts.setRealState("done");
                } else if("bluntActually".equals(state)){
                    operatingCostsItem.setBluntActuallyDate(new Date());
                    operatingCostsItem.setBluntActuallyAmt(Arith.round(operatingCosts.getBluntActuallyAmt() * proportionServeType.getProportion(),2));
                    operatingCosts.setRealState("done");
                }
                operatingCostsItemSet.add(operatingCostsItem);
            });
        } else {
            proportionServeTypeList.forEach(proportionServeType -> {
                List<OperatingCostsItem> costsItemList = operatingCostsItemSet.stream().filter(operatingCostsItem -> operatingCostsItem.getServeType().getId().equals(proportionServeType.getServeType().getId())).collect(Collectors.toList());
                OperatingCostsItem operatingCostsItem = costsItemList.get(0);
                //注意区分计提与实际
                if("provision".equals(state)){
                    operatingCostsItem.setAccrualDate(new Date());
                    operatingCostsItem.setAccrualAmt( Arith.round(amt * proportionServeType.getProportion(),2) + operatingCostsItem.getAccrualAmt());
                    operatingCosts.setAccrualState("done");
                } else if("actually".equals(state)){
                    operatingCostsItem.setRealDate(new Date());
                    operatingCostsItem.setRealAmt( Arith.round(amt * proportionServeType.getProportion(),2) + operatingCostsItem.getRealAmt());
                    operatingCosts.setRealState("done");
                } else if("bluntProvision".equals(state)){
                    operatingCostsItem.setBluntProvisionDate(new Date());
                    operatingCostsItem.setBluntProvisionAmt(Arith.round(amt * proportionServeType.getProportion(),2) + operatingCostsItem.getBluntProvisionAmt());
                    operatingCosts.setRealState("done");
                } else if("bluntActually".equals(state)){
                    operatingCostsItem.setBluntActuallyDate(new Date());
                    operatingCostsItem.setBluntActuallyAmt(Arith.round(amt * proportionServeType.getProportion(),2) + operatingCostsItem.getBluntActuallyAmt());
                    operatingCosts.setRealState("done");
                }
            });
        }
        return operatingCostsItemSet;
    }

    /**
     * 生成经营成本明细---不是按照部门统计数据
     * @param map
     * @param typeCost
     * @param company
     */
    private void saveNewOperatingCots(Map map,TypeCost typeCost,PartyRole company,Dept dept){
        String state = map.get("state").toString();
        double amt = Double.parseDouble(map.get("amt").toString());
        String sourceReceipt = map.get("sourceReceipt").toString();
        PartyRole person = null;
        PartyRole declareCompany = null;

        NewOperatingCosts newOperatingCosts = new NewOperatingCosts();
        newOperatingCosts.setSourceReceipt(sourceReceipt);
        if (!ObjectUtils.isEmpty(map.get("sourceId"))){
            newOperatingCosts.setSourceId(map.get("sourceId").toString());
        }
        newOperatingCosts.setCompany(company);
        newOperatingCosts.setTypeCost(typeCost);
        newOperatingCosts.setDept(dept);
        if (!ObjectUtils.isEmpty(map.get("person"))){
            person = MapUtil.getO(map.get("person"),PartyRole.class);
            newOperatingCosts.setPerson(person);
        }
        if (!ObjectUtils.isEmpty(map.get("declareCompany"))){
            declareCompany = MapUtil.getO(map.get("declareCompany"),PartyRole.class);
            newOperatingCosts.setDeclareCompany(declareCompany);
        }
        newOperatingCosts.setYearMonth(DateUtil.parse(map.get("yearMonth").toString()));
        newOperatingCosts.setCostType(enumerationRepository.findOne(map.get("costType").toString()));
        if("provision".equals(state)){
            newOperatingCosts.setAccrualDate(new Date());
            newOperatingCosts.setAccrualAmt(amt);
        } else if("actually".equals(state)){
            newOperatingCosts.setRealDate(new Date());
            newOperatingCosts.setRealAmt(amt);
        } else if("bluntProvision".equals(state)){
            newOperatingCosts.setBluntProvisionDate(new Date());
            newOperatingCosts.setBluntProvisionAmt(amt);
        } else if("bluntActually".equals(state)){
            newOperatingCosts.setBluntActuallyDate(new Date());
            newOperatingCosts.setBluntActuallyAmt(amt);
        }
        newOperatingCosts.setNewOperatingCostsItems(saveNewOperatingCotsItem(new HashSet<>(),newOperatingCosts,state,amt));
        newOperatingCostsRepository.saveAndFlush(newOperatingCosts);
    }

    /**
     * 生成经营成本明细item
     * @param newOperatingCostsItems
     * @param newOperatingCosts
     * @param state
     * @param amt
     * @return
     */
    private Set<NewOperatingCostsItem> saveNewOperatingCotsItem(Set<NewOperatingCostsItem> newOperatingCostsItems, NewOperatingCosts newOperatingCosts, String state, Double amt){
        Date yearMonth = newOperatingCosts.getYearMonth();
        String months = DateUtil.format(yearMonth, "MM");
        String years = DateUtil.format(yearMonth, "YYYY");
        List<ProportionServeType> proportionServeTypeList = proportionServeTypeRepository.findByYearMonthAndDept(months,years,newOperatingCosts.getDept().getId());
        if (!CollectionUtils.isEmpty(proportionServeTypeList)){
            proportionServeTypeList.forEach(proportionServeType -> {
                NewOperatingCostsItem newOperatingCostsItem = new NewOperatingCostsItem();
                newOperatingCostsItem.setCostType(newOperatingCosts.getCostType());
                newOperatingCostsItem.setServeType(proportionServeType.getServeType());
                newOperatingCostsItem.setTypeCost(newOperatingCosts.getTypeCost());
                newOperatingCostsItem.setNewOperatingCosts(newOperatingCosts);
                //注意区分计提与实际
                if("provision".equals(state)){
                    newOperatingCostsItem.setAccrualDate(new Date());
                    newOperatingCostsItem.setAccrualAmt( Arith.round(newOperatingCosts.getAccrualAmt() * proportionServeType.getProportion(),2));
                    newOperatingCosts.setAccrualState("done");
                } else if("actually".equals(state)){
                    newOperatingCostsItem.setRealDate(new Date());
                    newOperatingCostsItem.setRealAmt( Arith.round(newOperatingCosts.getRealAmt() * proportionServeType.getProportion(),2));
                    newOperatingCosts.setRealState("done");
                } else if("bluntProvision".equals(state)){
                    newOperatingCostsItem.setBluntProvisionDate(new Date());
                    newOperatingCostsItem.setBluntProvisionAmt(Arith.round(newOperatingCosts.getBluntProvisionAmt() * proportionServeType.getProportion(),2));
                    newOperatingCosts.setRealState("done");
                } else if("bluntActually".equals(state)){
                    newOperatingCostsItem.setBluntActuallyDate(new Date());
                    newOperatingCostsItem.setBluntActuallyAmt(Arith.round(newOperatingCosts.getBluntActuallyAmt() * proportionServeType.getProportion(),2));
                    newOperatingCosts.setRealState("done");
                }
                newOperatingCostsItems.add(newOperatingCostsItem);
            });
        }
        return newOperatingCostsItems;
    }
}
